﻿using Flurl.Http;
using NovelDownload.Common;
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace NovelDownload
{
    /// <summary>
    /// 棉花糖小说网
    /// </summary>
    public class MhtNovelSite : NovelSiteBase, INovelSiteBase
    {
        public MhtNovelSite()
            :base() {}


        public MhtNovelSite(string siteName, string siteHomeUrl, string searchSubmitUrl, string baseDownloadUrl)
            :base(siteName, siteHomeUrl, searchSubmitUrl, baseDownloadUrl)
        {
        }


        /// <summary>
        /// 搜索小说
        /// </summary>
        /// <param name="keyword"></param>
        /// <returns></returns>
        public async Task<List<NovelInfo>> SearchNovel(string keyword)
        {
            List<NovelInfo> novels = new List<NovelInfo>();

            string cacheKey = $"{this.SiteName}_search_{keyword}";
            var cacheValue = MemoryCacheHelper.GetCacheItem<List<NovelInfo>>(cacheKey);
            if (cacheValue == null)
            {
                try
                {
                    string htmlCode = await this.SearchSubmitUrl.WithTimeout(10).PostUrlEncodedAsync(new { searchkey = keyword }).ReceiveString();
                    var doc = ParseHtml.GetDocument(htmlCode);
                    var trs = doc.QuerySelectorAll("table.grid tr");

                    for (int i = 1; i < trs.Length; i++)
                    {
                        var tds = trs[i].Children;

                        NovelInfo novel = new NovelInfo();

                        novel.NovelName = tds[0].FirstElementChild.InnerHtml;
                        novel.NovelLink = tds[0].FirstElementChild.Attributes["href"].Value;
                        novel.LatestChapter = tds[1].FirstElementChild.InnerHtml;
                        novel.Author = tds[2].InnerHtml;
                        novel.UpdateTime = tds[3].InnerHtml;

                        novels.Add(novel);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    return null;
                }

                MemoryCacheHelper.SetCacheItem(cacheKey, novels, TimeSpan.FromMinutes(5));
            }
            else
            {
                novels = cacheValue;
            }

            return novels;
        }


        /// <summary>
        /// 获取全部章节信息
        /// </summary>
        /// <param name="novelUrl"></param>
        /// <returns></returns>
        public async Task<List<ChapterInfo>> GetAllChapterInfo(string novelUrl)
        {
            List<ChapterInfo> chapters = new List<ChapterInfo>();

            string cacheKey = $"{this.SiteName}_{novelUrl}_chapter";
            var cacheValue = MemoryCacheHelper.GetCacheItem<List<ChapterInfo>>(cacheKey);

            if (cacheValue == null)
            {
                string htmlCode = await novelUrl.GetStringAsync();
                var doc = ParseHtml.GetDocument(htmlCode);
                var dlHtml = doc.QuerySelector("div.novel_list dl").InnerHtml;

                // 获取章节信息
                string patter = "dd><a href=\"(.*?)\">(.*?)</a></dd>";
                Regex regex = new Regex(patter);
                MatchCollection matchs = regex.Matches(dlHtml);
                if (matchs == null) { return null; }

                foreach (Match m in matchs)
                {
                    ChapterInfo chapter = new ChapterInfo();
                    chapter.ChapterTitle = m.Groups[2].Value.Trim();
                    chapter.ChapterLink = novelUrl + m.Groups[1].Value;

                    chapters.Add(chapter);
                }

                MemoryCacheHelper.SetCacheItem(cacheKey, chapters, TimeSpan.FromMinutes(5));
            }
            else
            {
                chapters = cacheValue;
            }

            return chapters;
        }


        /// <summary>
        /// 获取章节内容
        /// </summary>
        /// <param name="chapterUrl"></param>
        /// <returns></returns>
        public async Task<string> GetChapterContent(string chapterUrl)
        {
            string contentStr;

            string cacheKey = $"{this.SiteName}_chapterContent_{chapterUrl}";
            var cacheValue = MemoryCacheHelper.GetCacheItem<string>(cacheKey);

            if (cacheValue == null)
            {
                string htmlCode = await chapterUrl.GetStringAsync();
                var doc = ParseHtml.GetDocument(htmlCode);
                var content = doc.QuerySelector("div.content");
                var conrs = content.QuerySelectorAll("div.con_r");
                var conls = content.QuerySelectorAll("div.con_l");
                var ps = content.QuerySelectorAll("p");
                foreach (var conr in conrs)
                {
                    conr.Remove();
                }
                foreach (var conl in conls)
                {
                    conl.Remove();
                }
                foreach (var p in ps)
                {
                    p.Remove();
                }
                //contentStr = content.InnerHtml.Replace(c).Replace("<br>", "");
                var contentStrSb = new StringBuilder(content.InnerHtml);
                contentStr = contentStrSb.Replace("&nbsp;", "").Replace("<br>", "").ToString();

                MemoryCacheHelper.SetCacheItem<string>(cacheKey, contentStr, TimeSpan.FromMinutes(5));
            }
            else
            {
                contentStr = cacheValue;
            }
            return contentStr;
        }



        /// <summary>
        /// 下载
        /// </summary>
        /// <param name="savePath"></param>
        /// <param name="downloadUrl"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public async Task<string> DownloadNovel(string savePath, string downloadUrl, string fileName)
        {
            try
            {
                string path = await downloadUrl.WithTimeout(10).DownloadFileAsync(savePath, fileName);
                return path;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return null;
            }
        }
    }
}
